home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Hot Mix 17
/
Hot Mix 17.iso
/
HM17_SGI
/
research
/
lib
/
read_ascii.pro
< prev
next >
Wrap
Text File
|
1997-07-08
|
27KB
|
879 lines
; $Id: read_ascii.pro,v 1.8 1997/04/08 17:36:58 stevek Exp $
;
; Copyright (c) 1996-1997, Research Systems, Inc. All rights reserved.
; Unauthorized reproduction prohibited.
;+
; NAME:
; READ_ASCII
;
; PURPOSE:
; Read data from an ASCII file into IDL.
;
; CATEGORY:
; Input/Output.
;
; CALLING SEQUENCE:
; data = READ_ASCII(file)
;
; INPUTS:
; file - Name of file to read.
;
; INPUT KEYWORD PARAMETERS:
; record_start - 1st sequential "record" (see DESCRIPTION) to read.
; Default = 0 (the first record of the file).
; num_records - Number of records to read.
; Default = Read up to and including the last record.
;
; template - ASCII file template (e.g., generated by function
; ASCII_TEMPLATE) describing attributes of the file
; to read. Specific attributes contained in the
; template may be overridden by keywords below.
; Default = (see the keywords below).
;
; data_start - Number of lines of header to skip.
; Default (if no template) = 0L.
; delimiter - Character that delimits fields.
; Default (if no template) = '' = use fields(*).loc.
; missing_value - Value to replace any missing/invalid data.
; Default (if no template) = !VALUES.F_NAN.
; comment_symbol - String identifying comments
; (from comment_symbol to the next end-of-line).
; Default (if no template) = '' = no comments.
; fields - Descriptions of the data fields, formatted as
; an array of structures containing the tags:
; name = name of the field (string)
; type = type of field as returned by SIZE (long)
; loc = offset from the beginning of line to
; the start of the field (long)
; group = sequential group the field is in (int)
; Default (if no template) =
; {name:'field', type:4L, loc:0L, group:0}.
;
; verbose - If set, print runtime messages.
; Default = Do not print them.
;
; OUTPUT KEYWORD PARAMETERS:
; header - The header read (string array of length
; data_start). If no header, empty string returned.
;
; count - The number of records read.
;
; OUTPUTS:
; The function returns an anonymous structure, where each field in
; the structure is a "field" of the data read (see DESCRIPTION).
; If no records are read, 0 is returned.
;
; COMMON BLOCKS:
; None.
;
; SIDE EFFECTS:
; None.
;
; RESTRICTIONS:
; See DESCRIPTION.
;
; DESCRIPTION:
; ASCII files handled by this routine consist of an optional header
; of a fixed number of lines, followed by columnar data. Files may
; also contain comments, which exist between a user-specified comment
; string and the corresponding end-of-line.
;
; One or more rows of data constitute a "record." Each data element
; within a record is considered to be in a different column, or "field."
; Adjacent fields may be "grouped" into multi-column fields.
; The data in one field must be of, or promotable to, a single
; type (e.g., FLOAT).
;
; EXAMPLES:
; ; Using default file attributes.
; data = READ_ASCII(file)
;
; ; Setting specific file attributes.
; data = READ_ASCII(file, DATA_START=10)
;
; ; Using a template to define file attributes.
; data = READ_ASCII(file, TEMPLATE=template)
;
; ; Using a template to define file attributes,
; ; and overriding some of those attributes.
; data = READ_ASCII(file, TEMPLATE=template, DATA_START=10)
;
; ; Using the ASCII_TEMPLATE GUI to generate a template in place.
; data = READ_ASCII(file, TEMPLATE=ASCII_TEMPLATE(file))
;
; ; An example defining fields by hand.
; fields = REPLICATE({name:'', type:0L, loc:0L, group:0}, 2, 3)
; num = N_ELEMENTS(fields)
; fields(*).name = 'field' + STRTRIM(STRING(INDGEN(num) + 1), 2)
; fields(*).type = REPLICATE(4L, num)
; fields(*).loc = [0L,10L, 0L,15L, 0L,12L]
; fields(*).group = INDGEN(num)
; data = READ_ASCII(file, FIELDS=fields)
;
; ; Another example defining fields by hand.
; void = {sMyStructName, name:'', type:0L, loc:0L, group:0}
; fields = [ [ {sMyStructName, 'frog', (SIZE(''))(1), 0L, 0}, $
; {sMyStructName, 'bird', (SIZE(0 ))(1), 15L, 1} ], $
; [ {sMyStructName, 'fish', (SIZE(0.))(1), 0L, 2}, $
; {sMyStructName, 'bear', (SIZE(0D))(1), 15L, 3} ], $
; [ {sMyStructName, 'boar', (SIZE(0B))(1), 0L, 4}, $
; {sMyStructName, 'nerd', (SIZE(OL))(1), 15L, 5} ] ]
; data = READ_ASCII(file, FIELDS=fields)
;
; DEVELOPMENT NOTES:
;
; - see ???,!!!,xxx in the code
;
; - error check input 'delimiter' to be a string (not a byte)
;
; - finish implementing new 'fields' input kw
; (old approach had separate kw for each attribute of a field)
;
; MODIFICATION HISTORY:
; AL & RPM, 8/96 - Written.
;
;-
;
; ROUTINES:
; fun ra_parse_value - parse a value
; pro ra_resize_pointers - increase the size of the data vectors
; pro ra_parse_d_values - parse delimited values
; pro ra_get_next_record - read in the next record
; fun ra_read_from_templ - read a file given an ASCII file template
; fun ra_valid_template - check if a template is valid
; fun ra_stringit - convert to string and remove white space
; fun ra_check_file - check validity of input file
; fun read_ascii - the main routine
; -----------------------------------------------------------------------------
;
; Purpose: Given a start and end location into a string, parse out the
; appropriate numerical or string value. In the case of a blank
; string or any error, substitute in the missing value.
;
function ra_parse_value, line, type, sptr, len, $
nlut=nlut, missing_value=missing_value
; Grab the sub string and remove leading/trailing white space.
;
sub_str = strtrim(strmid(line, sptr, len), 2)
if (type eq 7) then $ ; string
return, sub_str $
else begin
; If the string is empty, return missing value.
;
; Else if the string doesn't start as a proper number
; (i.e., with 0-9,+,-,.), return missing value.
;
if ((sub_str eq '') or $
((nlut(byte(strmid(sub_str,0,1))))(0) eq 0)) then $
return, missing_value ; missing
case type of
0: return, 0B ; ??? undefined -> 0B ???
1: return, byte(fix(sub_str)) ; byte
2: return, fix(sub_str) ; int
3: return, long(sub_str) ; long
4: return, float(sub_str) ; float
5: return, double(sub_str) ; double
6: return, complex(sub_str) ; complex
endcase
endelse
end ; ra_parse_value
; -----------------------------------------------------------------------------
;
; Purpose: Go through the array of pointers to arrays and increase the
; size of each array by blk_size elements.
;
pro ra_resize_pointers, p_vals, blk_size
for i=0, n_elements(p_vals)-1 do begin
if (ptr_valid(p_vals(i))) then begin
info = size(*p_vals(i))
*p_vals(i) = [*p_vals(i), make_array(blk_size, type=info(info(0)+1))]
endif
endfor
end ; ra_resize_pointers
; -----------------------------------------------------------------------------
;
; Purpose: Parse out values from a line of text which are separated by
; a given delimiter.
;
pro ra_parse_d_values, line, types, p_vals, floc, rec_count, $
delimit, nlut, missing_value
; If delimiter is space, compress and remove leading/trailing spaces.
;
if (delimit eq 32B) then line = strtrim(strcompress(line), 2)
bline = byte(line)
; Find where the delimiters are.
;
ptr = where(bline eq delimit, bcount)
if (bcount eq 0) then begin
ptr = [-1, n_elements(bline)+1]
bcount = 0
endif else $
ptr = [-1, ptr, n_elements(bline)+1]
; Loop for each field of the line.
;
for i=0, bcount<(n_elements(types)-floc-1) do $
; Parse the field if not skipping it.
;
if (types(floc+i) gt 0) then begin
(*p_vals(floc+i))(rec_count) = $
ra_parse_value(line, types(floc+i), ptr(i)+1, ptr(i+1)-ptr(i)-1, $
nlut=nlut, missing_value=missing_value)
endif
end ; ra_parse_d_values
; -----------------------------------------------------------------------------
;
; Purpose: Read in the next n lines of text (skipping blank lines and
; commented lines signified by template.commentSymbol at start;
; also throw away comment portions of regular lines).
;
pro ra_get_next_record, template, unit, lines, end_reached=end_reached
;
catch, error_status
if (error_status ne 0) then begin
end_reached = 1B
return
endif
;
line = ''
count = 0
end_reached = 0B
; Checking for comments...
;
if (template.commentSymbol ne '') then begin
while (count lt n_elements(lines)) do begin
readf, unit, line
pos = strpos(line, template.commentSymbol, 0)
if (strtrim(line,2) ne '' and pos(0) ne 0) then begin
if (pos(0) eq -1) then lines(count) = line $
else lines(count) = strmid(line,0,pos(0)-1)
count = count + 1
endif
endwhile
; NOT checking for comments...
;
endif else begin
while (count lt n_elements(lines)) do begin
readf, unit, line
if (strtrim(line,2) ne '') then begin
lines(count) = line
count = count + 1
endif
endwhile
endelse
end ; ra_get_next_record
; -----------------------------------------------------------------------------
;
; Purpose: Given a template structure, open an ASCII file and parse out the
; numerical and string values based upon the parameters of the
; given template.
;
; (a) white space separates fields lined up in columns
; (b) a delimiter character separates fields
;
; Note: When skipping to the start of the data, blank lines ARE included
; as lines to skip, but once you get to the data, subsequent blank
; lines (as well as comment lines) are ignored.
;
; Function returns an array of pointers to the data read;
; if no data read, 0 is returned.
;
function ra_read_from_templ, $
name, $ ; IN: name of ASCII file to read
template, $ ; IN: ASCII file template
start_record, $ ; IN: first record to read
records_to_read, $ ; IN: number of records to read
doVerbose, $ ; IN: 1B = print runtime messages
num_fields_read, $ ; OUT: number of fields successfully read
fieldNames, $ ; OUT: associated name of each field read
rec_count, $ ; OUT: number of records successfully read
header=header ; OUT: (opt) header read
widget_control, /hourglass
; Set default numbers.
;
num_fields_read = 0
rec_count = 0l
; Catch errors.
;
catch, error_status
if (error_status ne 0) then begin
print,'Unexpected Error: ' + !err_string
rec_count = 0l
return, 0
endif
; Open the file.
;
openr, unit, name, /get_lun
; Create character (byte) lookup table.
;
nlut = bytarr(256)
nlut(48:57) = 1 ; 0 thru 9
nlut(byte('-')) = 1 ; -
nlut(byte('+')) = 1 ; +
nlut(byte('.')) = 1 ; .
; Set various parameters.
;
blk_size = 1000
lines_per_record = n_elements(template.fieldCount)
num_fields = template.fieldCount
tot_num_fields = total(template.fieldCount)
types = template.fieldTypes
locs = template.fieldLocations
; Define an array of variables for each field.
;
p_vals = ptrarr(tot_num_fields)
for i=0, tot_num_fields-1 do $
if (types(i) gt 0) then $
p_vals(i) = ptr_new(make_array(blk_size, type=types(i)))
; Read the header and skip to the start of the data.
;
dataStart = template.dataStart
if (dataStart gt 0) then begin
if (doVerbose) then $
print, 'Reading header of ' + strtrim(string(dataStart), 2) + $
' lines ...', format='(A/)'
header = strarr(dataStart)
readf, unit, header
endif else $
header = ''
; Skip to the start of requested data.
;
lines = strarr(lines_per_record)
if ((doVerbose) and (start_record gt 0)) then $
print, 'Skipping ' + strtrim(string(start_record), 2) + ' records ...', $
format='(A/)'
for i = 0L, start_record-1 do $
ra_get_next_record, template, unit, lines
end_reached = 0B
; ------------------------------------
; nice columned data...
; ------------------------------------
;
if (template.delimiter eq 0B) then begin
while (((rec_count lt records_to_read) or (records_to_read eq 0)) and $
(not end_reached)) do begin
; Read the next record.
;
ra_get_next_record, template, unit, lines, end_reached=end_reached
if (not end_reached) then begin
floc = 0
;xxx
if (doVerbose) then $
print, 'Processing sequential record ' + $
strtrim(string(rec_count+1), 2) + ' ...'
; Loop for each line in a record, parsing values.
;
for j=0, lines_per_record-1 do begin
for k=0, num_fields(j)-1 do begin
if (types(floc+k) gt 0) then begin
if (k eq num_fields(j)-1) then $
len = strlen(lines(j)) - locs(floc+k) $
else $
len = locs(floc+k+1) - locs(floc+k)
(*p_vals(floc+k))(rec_count) = ra_parse_value(lines(j), $
types(floc+k), locs(floc+k), len, $
nlut=nlut, missing=template.missingValue)
endif
endfor
floc = floc + num_fields(j)
endfor
rec_count = rec_count + 1l
if (rec_count mod blk_size eq 0) then $
ra_resize_pointers, p_vals, blk_size
endif
endwhile
; ------------------------------------
; data separated by a delimiter...
; ------------------------------------
;
endif else begin
while (((rec_count lt records_to_read) or (records_to_read eq 0)) and $
(not end_reached)) do begin
; Read the next record.
;
ra_get_next_record, template, unit, lines, end_reached=end_reached
if (not end_reached) then begin
floc = 0
;xxx
if (doVerbose) then $
print, 'Processing sequential record ' + $
strtrim(string(rec_count+1), 2) + ' ...'
; Loop for each line in a record, parsing values.
;
for i=0, lines_per_record-1 do begin
ra_parse_d_values, lines(i), types, p_vals, floc, $
rec_count, template.delimiter, nlut, template.missingValue
floc = long(total(num_fields(0:i)))
endfor
rec_count = rec_count + 1l
if (rec_count mod blk_size eq 0) then $
ra_resize_pointers, p_vals, blk_size
endif
endwhile
endelse
; ------------------------------------
free_lun, unit
if (doVerbose) then $
print, 'Total records read: ' + strtrim(string(rec_count), 2), $
format='(A/)'
; If records were read ...
;
if (rec_count gt 0) then begin
; Set the output arrays to exactly the correct size.
;
for i=0, tot_num_fields-1 do $
if (p_vals(i) ne ptr_new()) then $
*p_vals(i) = (*p_vals(i))(0:rec_count-1)
; Check the groups array and arrange the output pointers into
; (potentially) groups of 2-D arrays.
;
groups = template.fieldGroups
; Don't include any groups which are skipped fields.
;
ptr = where(types eq 0, numSkip)
for i=0, numSkip-1 do groups(ptr(i)) = max(groups) + 1
;
; Concatenate 1-D arrays into multi arrays based upon groupings.
;
uptr = uniq(groups, sort(groups))
if (n_elements(uptr) lt n_elements(groups)) then begin
for i=0, n_elements(uptr)-1 do begin
lptr = where(groups eq groups(uptr(i)), lcount)
if (lcount gt 1) then begin
p_new = p_vals(lptr(0))
for j=1,lcount-1 do begin
*p_new = [[*p_new],[*p_vals(lptr(j))]]
ptr_free, p_vals(lptr(j))
p_vals(lptr(j)) = ptr_new()
endfor
*p_new = transpose(*p_new)
endif
endfor
endif
; Return the pointers that contain data, if any.
; and the associated fieldNames for these pointers
;
ptr = where(p_vals ne ptr_new(), num_fields_read)
if (num_fields_read gt 0) then begin ; data successfully read
fieldNames = template.fieldNames(ptr)
return, p_vals(ptr)
endif else begin ; no data read
rec_count = 0l
return, 0
endelse
endif else $ ; no data read
return, 0
end ; ra_read_from_templ
; -----------------------------------------------------------------------------
;
; Purpose: Return 1B if the template is valid, else 0B.
;
function ra_valid_template, $
template, $ ; IN: template to check
message ; OUT: error message if the template is not valid
message = ''
; Make sure it's a structure.
;
sz = size(template)
if (sz(sz(0)+1) ne 8) then begin
message = 'Template is not a structure.'
RETURN, 0B
endif
; Get tag names and make sure version field is present.
;
tagNamesFound = TAG_NAMES(template)
void = WHERE(tagNamesFound eq 'VERSION', count)
if (count ne 1) then begin
message = 'Version field missing from template.'
RETURN, 0B
endif
; Do checking based on version.
;
case (template.version) of
1.0: begin
; Set the names of the required tags (version alread checked).
;
tagNamesRequired = STRUPCASE([ $
'dataStart', 'delimiter', 'missingValue', 'commentSymbol', $
'fieldCount', 'fieldTypes', 'fieldNames', 'fieldLocations', $
'fieldGroups'])
; Check that all of the required tags are present.
;
for seqTag = 0, N_ELEMENTS(tagNamesRequired)-1 do begin
tag = tagNamesRequired(seqTag)
void = WHERE(tagNamesFound eq tag, count)
if (count ne 1) then begin
message = tag + ' field missing from template.'
RETURN, 0B
endif
endfor
end
else: begin
message = 'The only recognized template version is 1.0 (float).'
RETURN, 0B
end
endcase
; Return that the template is valid.
;
RETURN, 1B
end ; ra_valid_template
; -----------------------------------------------------------------------------
;
; Purpose: Convert to string and remove extra white space.
;
function ra_stringit, value
result = STRTRIM( STRCOMPRESS( STRING(value) ), 2 )
num = N_ELEMENTS(result)
if (num le 1) then RETURN, result
; If two or more values, concatenate them.
;
delim = ' '
ret = result(0)
for i = 1, num-1 do $
ret = ret + delim + result(i)
RETURN, ret
end ; ra_stringit
; -----------------------------------------------------------------------------
;
; Purpose: Check that the input filename is a string, exists, and appears
; to be ASCII... also if the file is just columned ascii data,
; then guess at the number of default columns of data.
;
function ra_check_file, fname, default_num_columns=default_num_columns
catch, error_status
if (error_status ne 0) then begin
if (n_elements(unit) gt 0) then free_lun, unit
return, -3 ; unexpected error reading from file
endif
;
info = size(fname)
if (info(info(0)+1) ne 7) then return, -1 ; filename isn't a string
;
openr, unit, fname, error=error, /get_lun
if (error eq 0) then begin
finfo = fstat(unit)
; set non-ascii values in lookup table
;
lut = bytarr(256) + 1b
lut[7:13] = 0b
lut[32:127] = 0b
data = bytarr(32767<finfo.size, /nozero)
readu, unit, data
carriage_return = (total(data eq 10b) gt 0 or total(data eq 13b) gt 0)
if (carriage_return eq 0) then begin
; looks like a binary file
;
free_lun, unit
return, -4
endif
non_printable = (total(lut(data)) gt 0)
if (non_printable) then begin
; looks like a binary file
;
free_lun, unit
return, -4
endif
; everything looks ok, now guess at the number of columns...
;
point_lun, unit, 0
line = ''
readf, unit, line
free_lun, unit
bline = byte(strtrim(strcompress(line),2))
ptr = where(bline eq 32, num_spaces)
default_num_columns = num_spaces + 1
endif else $
return, -2 ; unable to open file
end
; -----------------------------------------------------------------------------
;
; Purpose: The main routine.
;
function read_ascii, $
file, $ ; IN:
RECORD_START=recordStart, $ ; IN: (opt)
NUM_RECORDS=numRecords, $ ; IN: (opt)
TEMPLATE=template, $ ; IN: (opt)
DATA_START=dataStart, $ ; IN: (opt)
DELIMITER=delimiter, $ ; IN: (opt)
MISSING_VALUE=missingValue, $ ; IN: (opt)
COMMENT_SYMBOL=commentSymbol, $ ; IN: (opt)
FIELDS=fields, $ ; IN: (opt)
VERBOSE=verbose, $ ; IN: (opt)
HEADER=header, $ ; OUT: (opt)
COUNT=count ; OUT: (opt)
;xxx
;later add a VERSION kw ?
; Set to return to caller on error.
;
ON_ERROR, 2
; ON_ERROR, 0
; Set some defaults.
;
count = 0
currentVersion = 1.0
doVerbose = KEYWORD_SET(verbose)
; If no file specified, use DIALOG_PICKFILE
;
if (n_elements(file) eq 0) then begin
file = DIALOG_PICKFILE(/MUST_EXIST)
if (file eq '') then RETURN, 0
endif
;
; check that the file is readable and appears to be ASCII
ret = ra_check_file(file, default_num_columns=default_num_columns)
case ret of
-1: MESSAGE, 'File name must be a string.'
-2: MESSAGE, 'File "' + file + '" not found.'
-3: MESSAGE, 'Error Reading from file "' + file + '"
-4: MESSAGE, 'File "' + file + '" is not an ASCII file.'
else:
endcase
; Set which records to read.
;
if (N_ELEMENTS(recordStart) ne 0) then recordStartUse = recordStart $
else recordStartUse = 0
if (N_ELEMENTS(numRecords) ne 0) then numRecordsUse = numRecords $
else numRecordsUse = 0
; ---------------------------------------
; Set default file attributes.
; ---------------------------------------
; If a template was input, then use those attributes.
;
if (N_ELEMENTS(template) gt 0) then begin
; Make sure the template is valid.
;
if (not ra_valid_template(template, message)) then $
MESSAGE, message
; Use the template's attributes as default.
;
versionUse = template.version
dataStartUse = template.dataStart
delimiterUse = STRING(template.delimiter)
missingValueUse = template.missingValue
commentSymbolUse = template.commentSymbol
fieldCountUse = template.fieldCount
fieldTypesUse = template.fieldTypes
fieldNamesUse = template.fieldNames
fieldLocationsUse = template.fieldLocations
fieldGroupsUse = template.fieldGroups
; Get the final number of fields.
;
if (N_ELEMENTS(fieldCount) ne 0) then $
fieldCountUse = fieldCount
numFields = TOTAL(fieldCountUse)
; No template input, so set defaults by hand.
;
endif else begin
; Set scalar defaults.
;
versionUse = currentVersion
dataStartUse = 0L
delimiterUse = ' '
missingValueUse = 0.0
commentSymbolUse = ''
; use best guess of default number of fields without any template
; information to go on...
numFields = (fieldCountUse = default_num_columns)
; Set vector defaults.
;
fieldTypesUse = REPLICATE(4L, numFields)
digits_str = strtrim(string(strlen(strtrim(string(numFields),2))),2)
fstr = '(i' + digits_str + '.' + digits_str + ')'
fieldNamesUse = 'field' + STRING(INDGEN(numFields)+1, format=fstr)
fieldLocationsUse = LONARR(numFields)
fieldGroupsUse = INTARR(numFields)
endelse
; ---------------------------------------
; Optionally override the attributes.
; ---------------------------------------
if (N_ELEMENTS(dataStart) ne 0) then $
dataStartUse = dataStart
if (N_ELEMENTS(delimiter) ne 0) then $
delimiterUse = delimiter
if (N_ELEMENTS(missingValue) ne 0) then $
missingValueUse = missingValue
if (N_ELEMENTS(commentSymbol) ne 0) then $
commentSymbolUse = commentSymbol
if (N_ELEMENTS(fieldTypes) ne 0) then $
fieldTypesUse = fieldTypes
if (N_ELEMENTS(fieldNames) ne 0) then $
fieldNamesUse = fieldNames
if (N_ELEMENTS(fieldLocations) ne 0) then $
fieldLocationsUse = fieldLocations
if (N_ELEMENTS(fieldGroups) ne 0) then $
fieldGroupsUse = fieldGroups
; ---------------------------------------
; Error check the field data.
;
lengths = [ $
N_ELEMENTS(fieldTypesUse), $
N_ELEMENTS(fieldNamesUse), $
N_ELEMENTS(fieldLocationsUse), $
N_ELEMENTS(fieldGroupsUse) $
]
if (TOTAL(ABS(lengths - SHIFT(lengths, 1))) ne 0) then $
MESSAGE, 'Field data (types/names/locs/groups) not the same length.'
; Set the template to use.
;
templateUse = { $
version: versionUse, $
dataStart: dataStartUse, $
delimiter: BYTE(delimiterUse), $
missingValue: missingValueUse, $
commentSymbol: commentSymbolUse, $
fieldCount: fieldCountUse, $
fieldTypes: fieldTypesUse, $
fieldNames: fieldNamesUse, $
fieldLocations: fieldLocationsUse, $
fieldGroups: fieldGroupsUse $
}
; Print verbose information.
;
if (doVerbose) then begin
PRINT, 'Using the following file attributes ...', FORMAT='(/A)'
PRINT, ' Data Start: ' + STRTRIM(STRING(dataStartUse), 2)
PRINT, ' Delimiter: ' + $
STRTRIM(STRING(FIX(BYTE(delimiterUse))), 2) + 'B'
PRINT, ' Missing Value: ' + STRTRIM(STRING(missingValueUse), 2)
PRINT, ' Comment Symbol: ' + commentSymbolUse
PRINT, ' Field Counts: ' + ra_stringit(fieldCountUse)
PRINT, ' Field Types : ' + ra_stringit(fieldTypesUse)
PRINT, ' Field Names : ' + ra_stringit(fieldNamesUse)
PRINT, ' Field Locs : ' + ra_stringit(fieldLocationsUse)
PRINT, ' Field Groups: ' + ra_stringit(fieldGroupsUse)
PRINT, ' Template Version: ' + STRTRIM(STRING(versionUse), 2)
PRINT
endif
; Try to read the file.
;
pData = ra_read_from_templ(file, templateUse, recordStartUse, $
numRecordsUse, doVerbose, numFieldsRead, FieldNames, count, header=header)
; Return zero if no records read.
;
if (count eq 0) then RETURN, 0
; Put the fields into a structure.
;
data = create_struct(strcompress(FieldNames(0),/rem), *pData(0))
for i=1, numFieldsRead-1 do $
data = create_struct(data, strcompress(FieldNames(i),/rem), *pData(i))
; Clean up the heap data.
;
for i = 0, numFieldsRead-1 do $
PTR_FREE, pData(i)
; Print verbose information.
;
if (doVerbose) then begin
PRINT, 'Output data ...'
HELP, data, /STRUCTURES
PRINT
endif
; Return the structure.
;
RETURN, data
end ; read_ascii
; -----------------------------------------------------------------------------